<template>
	<div class="body-analysis">
		<Header cNum="2" />
		<!-- 主内容 -->
		<el-row class="main">
			<!-- 算法选择 -->
			<el-col :span="7" class="section">
				<h3>算法选择</h3>
				<div class="content1">
					<div class="top">
						<el-select v-model="isPublic" placeholder="请选择公有算法还是私有算法" @change="toAlgo">
							<el-option label="公有算法" :value="true" />
							<el-option label="私有算法" :value="false" />
						</el-select>
					</div>
					<div class="top">
						<el-select v-model="language" placeholder="请选择语言" @change="toLanguage">
							<el-option v-for="l in languageList" :key="l" :label="l" :value="l"></el-option>
							<template #empty>
								<span>{{ lText }}</span>
							</template>
						</el-select>
						<el-select v-model="algorithm" placeholder="请选择算法" @change="selectAlgorithm">
							<el-option
								v-for="a in algoList"
								:key="a.algoId"
								:label="a.algoName"
								:value="a.algoId"
							></el-option>
							<template #empty>
								<span>{{ aText }}</span>
							</template>
						</el-select>
					</div>
					<div class="content">
						{{ algorithmContent }}
					</div>
					<div class="bottom">
						<el-button @click="openUpload">上传私有算法</el-button>
					</div>
				</div>
			</el-col>

			<!-- 架构选择 -->
			<el-col :span="10" class="section">
				<h3>架构选择</h3>
				<div class="content2">
					<div class="operate">
						<el-popover :width="250" :visible="isShow">
							<template #reference>
								<el-icon @click="toOpen"><Operation /></el-icon>
							</template>
							<div class="card-list">
								<el-card
									v-for="a in architectList"
									:key="a.id"
									shadow="hover"
									:class="{ select: a.id === architect_id }"
									@click="selectArchitect(a)"
								>
									{{ a.name }}
								</el-card>
							</div>
						</el-popover>
						<el-icon @click="toModify"><Edit /></el-icon>
						<el-icon @click="toClear"><Delete /></el-icon>
					</div>
					<div class="photo">
						<div class="img-div">
							<img class="bj" src="@/assets/images/jg1.png" alt="" />
							<img class="cpu-img" :src="aimg['cpu']" alt="" />
							<img class="flash-img" :src="aimg['flash']" alt="" />
							<img class="memory-img" :src="aimg['memory']" alt="" />
							<img class="acc-img" :src="aimg['acc']" alt="" />
						</div>
					</div>
					<div class="info">
						<p>
							<el-icon><Platform /></el-icon>
							架构基本信息
						</p>
						<el-descriptions column="1" direction="vertical" border class="detail">
							<el-descriptions-item
								v-for="(item, index) in details"
								:key="index"
								:label="item.label"
							>
								{{ item.value }}
							</el-descriptions-item>
						</el-descriptions>
					</div>
				</div>
			</el-col>

			<!-- 周期计算 -->
			<el-col :span="7" class="section">
				<h3>周期计算</h3>
				<div class="content3">
					<p>
						<el-icon><Document /></el-icon>
						分析结果
					</p>
					<div class="result">
						<div v-if="resultShow === true">
							<p>加法周期：{{ resultText.additionPeriod }}，共{{ resultTotal.aTotal }}个</p>
							<p>乘法周期：{{ resultText.multiPeriod }}，共{{ resultTotal.mTotal }}个</p>
							<p>加乘周期：{{ resultText.addMultiPeriod }}，共{{ resultTotal.amTotal }}个</p>
							<p>中断周期：{{ resultText.interruptPeriod }}，共{{ resultTotal.iTotal }}个</p>
						</div>
					</div>
					<p>
						<el-icon><DataLine /></el-icon>
						执行分析图
					</p>
					<div class="result">
						<div id="chart" style="width: 100%; height: 300px"></div>
					</div>
					<el-button type="primary" :disabled="isToRun" @click="toRun">运行</el-button>
				</div>
			</el-col>
		</el-row>
		<Footer />
		<ModifyArchitect
			v-if="isModifyShow"
			:isModifyShow="isModifyShow"
			:architectId="architect_id"
			:sdetail="sdetail"
			:simg="aimg"
			:accCards="accCards"
			:flashCards="flashCards"
			:cpuCards="cpuCards"
			:memoryCards="memoryCards"
			@submit="toSubmit"
			@cancle="toCancle"
		/>
		<el-dialog
			v-model="toUpload"
			title="上传算法"
			width="600"
			align-center
			:close-on-click-modal="false"
			:show-close="false"
		>
			<el-form :model="aForm" ref="aFormRef" :rules="rules" label-width="auto">
				<el-form-item label="算法名称：" prop="algoName">
					<el-input v-model="aForm.algoName" placeholder="请输入算法名称"></el-input>
				</el-form-item>
				<el-form-item label="算法类型：" prop="langType">
					<el-radio-group v-model="aForm.langType" @change="handleLangTypeChange">
						<el-radio label="C">C</el-radio>
						<el-radio label="Java">Java</el-radio>
						<el-radio label="Python">Python</el-radio>
					</el-radio-group>
				</el-form-item>
				<el-form-item label="选择算法文件：" prop="code">
					<el-upload
						ref="uploadRef"
						:auto-upload="false"
						:on-change="handleFileChange"
						:limit="1"
						:file-list="fileList"
					>
						<template #trigger>
							<el-button type="primary" :disabled="!aForm.langType">选择文件</el-button>
						</template>
						<template #tip>
							<div class="el-upload__tip">{{ getFileTipText }}</div>
						</template>
					</el-upload>
				</el-form-item>
			</el-form>
			<template #footer>
				<div class="dialog-footer">
					<el-button @click="canale">取消</el-button>
					<el-button type="primary" @click="submitForm">上传</el-button>
				</div>
			</template>
		</el-dialog>
	</div>
</template>

<script setup>
	import Header from '@/components/Header/index.vue'
	import Footer from '@/components/Footer/index.vue'
	import { ref, onMounted, computed } from 'vue'
	import { ElMessage } from 'element-plus'
	import ModifyArchitect from './ModifyArchitect.vue'
	import { userStore } from '@/store/user'
	import { algorithmList, frameworkList, result, upLoadAlgo } from '@/api/analysis'
	import { accList, flashList, memoryList, cpuList } from '@/api/framework'
	import * as echarts from 'echarts'

	const user = userStore()

	const isPublic = ref(null)
	// 存储选择的语言
	const language = ref('')
	const lText = ref('请先选择公有或私有算法')
	// 存储选择的算法
	const algorithm = ref('')
	const aText = ref('请先选择算法语言类型')
	// 存储算法内容
	const algorithmContent = ref('')
	// 存储算法列表
	const allAlgorithmList = ref([])

	const algorithm_id = ref(-1)
	const is_Public = ref()

	// 公有私有算法
	const toAlgo = async (v) => {
		const rData = (await algorithmList({ userId: user.id })).data
		if (rData.code == 200) {
			if (v == true) {
				allAlgorithmList.value = rData.publicAlgo
			} else {
				allAlgorithmList.value = rData.privateAlgo
			}
		}
		language.value = ''
		algorithm.value = ''
		algorithmContent.value = ''
		algorithm_id.value = -1
		if (allAlgorithmList.value.length === 0) {
			lText.value = '算法列表为空'
		}
	}

	// 存储语言列表
	const languageList = computed(() => {
		return allAlgorithmList.value.reduce((acc, item) => {
			if (!acc.includes(item.langType)) {
				acc.push(item.langType)
			}
			return acc
		}, [])
	})

	// 根据所选语言过滤后的算法列表
	const algoList = computed(() => {
		return allAlgorithmList.value.filter((a) => a.langType === language.value)
	})

	const toLanguage = () => {
		algorithm.value = ''
		algorithmContent.value = ''
		algorithm_id.value = -1
	}

	// 选择算法操作
	const selectAlgorithm = (v) => {
		algorithm_id.value = v
		is_Public.value = isPublic.value
		algorithmContent.value = algoList.value.find((item) => item.algoId === v).code
	}

	// 架构列表
	const architectList = ref([])

	const architect_id = ref(-1)

	const sdetail = ref({ cpu: 0, memory: 0, flash: 0, acc: 0 })

	const aimg = ref({ cpu: '', memory: '', flash: '', acc: '' })

	const isShow = ref(false)

	// 架构列表
	const toOpen = async () => {
		isShow.value = !isShow.value
		const rData = (await frameworkList({ userId: user.id })).data
		if (rData.code === 200) {
			architectList.value = rData.data
		} else {
			ElMessage.error(rData.msg)
		}
	}

	// 架构信息
	const details = ref([
		{
			type: 'cpu',
			label: 'CPU（中央处理器）',
			value: ' '
		},
		{
			type: 'memory',
			label: 'SD_Memory（内存卡）',
			value: ' '
		},
		{
			type: 'flash',
			label: 'AHB_PFlash（闪存）',
			value: ' '
		},
		{
			type: 'acc',
			label: 'AHB_Accelerator（加速器）',
			value: ' '
		}
	])

	//选择架构
	const selectArchitect = (a) => {
		architect_id.value = a.id
		sdetail.value['cpu'] = a['cpu'].id
		sdetail.value['acc'] = a['acc'].id
		sdetail.value['memory'] = a['memory'].id
		sdetail.value['flash'] = a['flash'].id

		aimg.value['cpu'] = a['cpu'].path
		aimg.value['acc'] = a['acc'].path
		aimg.value['memory'] = a['memory'].path
		aimg.value['flash'] = a['flash'].path

		details.value.forEach((detail) => {
			const type = detail.type
			if (a[type]) {
				detail.value = a[type].name
			}
		})
		ElMessage.success('成功选择架构：' + a.name)

		isShow.value = false
	}

	const isModifyShow = ref(false)

	//清除所选架构
	const toClear = () => {
		architect_id.value = -1
		sdetail.value['cpu'] = 0
		sdetail.value['acc'] = 0
		sdetail.value['memory'] = 0
		sdetail.value['flash'] = 0
		aimg.value['cpu'] = ''
		aimg.value['acc'] = ''
		aimg.value['memory'] = ''
		aimg.value['flash'] = ''

		details.value.forEach((detail) => {
			detail.value = ' '
		})

		ElMessage.success('已取消所选架构！')
	}

	const accCards = ref([])
	const flashCards = ref([])
	const cpuCards = ref([])
	const memoryCards = ref([])

	const toModify = async () => {
		accCards.value = (await accList()).data
		flashCards.value = (await flashList()).data
		cpuCards.value = (await cpuList()).data
		memoryCards.value = (await memoryList()).data
		isModifyShow.value = true
	}

	const toCancle = () => {
		isModifyShow.value = false
	}

	const toSubmit = () => {
		isModifyShow.value = false
		toOpen()
	}

	// 运行
	const isToRun = computed(() => {
		return !(algorithm_id.value !== -1 && architect_id.value !== -1)
	})

	const resultShow = ref(false)
	const resultText = ref({
		additionPeriod: '',
		multiPeriod: '',
		addMultiPeriod: '',
		interruptPeriod: ''
	})

	const calculateTotal = (str) => {
		try {
			return str ? JSON.parse(str).reduce((sum, [s, e]) => sum + (e - s), 0) : 0
		} catch {
			return 0
		}
	}

	const resultTotal = computed(() => {
		return {
			aTotal: calculateTotal(resultText.value.additionPeriod),
			mTotal: calculateTotal(resultText.value.multiPeriod),
			amTotal: calculateTotal(resultText.value.addMultiPeriod),
			iTotal: calculateTotal(resultText.value.interruptPeriod)
		}
	})

	const toRun = async () => {
		const params = {
			algoId: algorithm_id.value,
			architectId: architect_id.value,
			isPublic: is_Public.value
		}
		const rData = (await result(params)).data
		if (rData.code === 200) {
			resultShow.value = true
			resultText.value.additionPeriod = rData.analysis.additionPeriod
			resultText.value.multiPeriod = rData.analysis.multiPeriod
			resultText.value.addMultiPeriod = rData.analysis.addMultiPeriod
			resultText.value.interruptPeriod = rData.analysis.interruptPeriod
			showChart()
		} else {
			ElMessage.error(rData.msg)
		}
	}

	// 定义不同周期类型的颜色方案
	const categoryColors = [
		'#FF6B6B', // 红色系 - 加乘周期
		'#4ECDC4', // 绿色系 - 加法周期
		'#FFD166', // 黄色系 - 中断周期
		'#6A0572', // 紫色系 - 乘法周期
		'#1A936F' // 深绿系 - 其他
	]

	const Blank = (datas) => {
		return {
			name: '空白',
			type: 'bar',
			stack: 'Total',
			barWidth: 20,
			itemStyle: { borderColor: 'transparent', color: 'transparent' },
			emphasis: { itemStyle: { borderColor: 'transparent', color: 'transparent' } },
			data: datas
		}
	}

	const RangeBlock = (datas, color) => {
		return {
			name: '周期',
			type: 'bar',
			stack: 'Total',
			barWidth: 20,
			itemStyle: {
				color: color || '#333',
				borderRadius: 2
			},
			data: datas.map((item) => ({ value: item }))
		}
	}

	const barDataHandler = (data, colors) => {
		const res = []
		// 获取区间最多的一个项的区间数量
		let max = 0
		data.forEach((item) => {
			max = item.length > max ? item.length : max
		})

		for (let i = 0; i < max; i++) {
			const tempBlank = []
			const tempBlock = []
			const tempColors = []

			data.forEach((item, index) => {
				if (item.length > i) {
					tempBlank.push(i > 0 ? item[i][0] - item[i - 1][1] : item[i][0])
					tempBlock.push(item[i][1] - item[i][0])
					tempColors.push(colors[index % colors.length])
				} else {
					tempBlank.push(0)
					tempBlock.push(0)
					tempColors.push(null)
				}
			})

			// 现在每个类别有自己的颜色，需要为每个类别创建单独的 series
			data.forEach((_, index) => {
				// 创建这个类别的空白部分
				const blankData = tempBlank.map((val, idx) => (idx === index ? val : 0))
				res.push(Blank(blankData))

				// 创建这个类别的数据部分
				const blockData = tempBlock.map((val, idx) => (idx === index ? val : 0))
				res.push(RangeBlock(blockData, tempColors[index]))
			})
		}
		return res
	}

	let chart

	// 画图
	const showChart = () => {
		if (chart) {
			chart.dispose()
		}
		chart = echarts.init(document.getElementById('chart'))

		const data = Object.values(resultText.value).map((str) => JSON.parse(str))

		const option = {
			yAxis: {
				type: 'category',
				data: ['加法', '乘法', '加乘', '中断'],
				axisLabel: {
					interval: 0
				}
			},
			xAxis: {
				type: 'value',
				name: '时间',
				axisLine: {
					show: true
				}
			},
			series: barDataHandler(data, categoryColors)
		}

		chart.setOption(option)

		window.addEventListener('resize', () => {
			chart.resize()
		})
	}

	// 算法上传
	const toUpload = ref(false)
	const aFormRef = ref(null)

	const openUpload = () => {
		toUpload.value = true
	}

	const aForm = ref({
		algoName: '',
		langType: '',
		code: ''
	})

	const rules = {
		algoName: [{ required: true, message: '输入算法名', trigger: 'blur' }],
		langType: [{ required: true, message: '选择算法类型', trigger: 'change' }],
		code: [{ required: true, message: '请选择算法文件', trigger: 'change' }]
	}

	const fileList = ref([])
	const uploadRef = ref(null)

	// 根据算法类型获取对应的文件类型
	const acceptType = computed(() => {
		const typeMap = {
			C: '.c',
			Java: '.java',
			Python: '.py'
		}
		return typeMap[aForm.value.langType] || ''
	})

	// 获取文件提示文本
	const getFileTipText = computed(() => {
		if (!aForm.value.langType) {
			return '请先选择算法类型'
		}
		return `仅支持上传 ${acceptType.value} 文件，且只能选择一个文件`
	})

	// 处理算法类型变化
	const handleLangTypeChange = () => {
		// 清空已选择的文件
		if (uploadRef.value) {
			uploadRef.value.clearFiles()
		}
		fileList.value = []
		aForm.value.code = ''
	}

	const handleFileChange = (file) => {
		const fileName = file.name
		const fileExtension = fileName.substring(fileName.lastIndexOf('.') + 1)
		const expectedExtension = acceptType.value.replace('.', '')

		if (fileExtension !== expectedExtension) {
			ElMessage.error(`请选择 .${expectedExtension} 文件`)
			// 清空已选择的文件
			if (uploadRef.value) {
				uploadRef.value.clearFiles()
			}
			fileList.value = []
			aForm.value.code = ''
			return
		}

		const reader = new FileReader()
		reader.onload = (e) => {
			aForm.value.code = e.target.result
		}
		reader.onerror = () => {
			ElMessage.error('文件读取失败')
		}
		reader.readAsText(file.raw)
	}

	const submitForm = () => {
		aFormRef.value.validate(async (valid) => {
			if (valid) {
				const rData = (
					await upLoadAlgo({
						...aForm.value,
						userId: user.id
					})
				).data
				if (rData.code == 200) {
					ElMessage.success('私有算法上传成功，可重新查看并选择算法')
					isPublic.value = false
					language.value = ''
					algorithm.value = ''
					algorithmContent.value = ''
					algorithm_id.value = -1
					toUpload.value = false
					toAlgo()
				} else {
					ElMessage.error('私有算法上传失败，' + rData.msg)
				}
				uploadRef.value.clearFiles()
				aFormRef.value.resetFields()
			} else {
				return false
			}
		})
	}

	const canale = () => {
		uploadRef.value.clearFiles()
		aFormRef.value.resetFields()
		ElMessage.info('取消上传算法')
		toUpload.value = false
	}
</script>

<style lang="scss" scoped>
	.body-analysis {
		width: 100vw;
		height: 100vh;
	}

	.main {
		height: calc(100% - 175px);
		display: flex;
		padding: 1px;
	}

	.section {
		height: 100%;
		border: 1px solid #a9a9a9;
		h3 {
			border-bottom: 1px solid #a9a9a9;
			height: 35px;
			line-height: 35px;
			background: rgb(215, 215, 215);
			text-align: center;
			font-size: 20px;
			font-weight: bolder;
		}
	}

	.content1 {
		height: 100%;
		padding: 10px 10px;
		display: flex;
		flex-direction: column;
		align-items: center;
		.top {
			width: 100%;
			display: flex;
		}
		.content {
			margin: 10px 0;
			border: 2px solid #dcdfe6;
			border-radius: 2px;
			background: rgb(242, 242, 242);
			padding: 10px 20px;
			height: 62%;
			width: 100%;
			overflow: auto;
		}
		.bottom {
			width: 100%;
			.el-button {
				width: 100%;
				height: 35px;
				font-size: 18px;
			}
		}
	}

	.content2 {
		height: 100%;
		padding: 10px;
		.operate {
			height: 5%;
			.el-icon {
				color: #777;
				font-size: 24px;
				margin-right: 15px;
				cursor: pointer;
				&:hover {
					color: #000;
				}
			}
		}
		.photo {
			height: 45%;
			display: flex;
			justify-content: center;
			align-items: center;
			.img-div {
				height: 100%;
				position: relative;
				.bj {
					height: 100%;
				}
				img[src=''] {
					display: none;
				}
				.cpu-img {
					height: 40px;
					position: absolute;
					left: 14%;
					top: 24%;
				}
				.flash-img {
					height: 45px;
					position: absolute;
					left: 20%;
					bottom: 12%;
				}
				.memory-img {
					height: 45px;
					position: absolute;
					right: 21%;
					top: 23%;
				}
				.acc-img {
					height: 50px;
					position: absolute;
					right: 14%;
					bottom: 12%;
				}
			}
		}
		.info {
			height: 42%;
			p {
				height: 30px;
				display: flex;
				align-items: center;
				font-size: 16px;
				margin-bottom: 5px;
			}
			.detail {
				height: calc(100% - 40px);
				overflow: auto;
				:deep(.el-descriptions__label) {
					line-height: 20px;
					font-weight: normal;
				}
				:deep(.el-descriptions__content) {
					line-height: 30px;
					font-weight: bolder;
				}
			}
		}
	}

	.content3 {
		height: 100%;
		padding: 10px;
		p {
			height: 30px;
			display: flex;
			align-items: center;
			font-size: 16px;
		}
		.result {
			border: 2px solid #dcdfe6;
			border-radius: 2px;
			background: rgb(242, 242, 242);
			padding: 10px;
			height: 33%;
			width: 100%;
			overflow: auto;
		}
		.el-button {
			margin-top: 10px;
			width: 100%;
			height: 35px;
			font-size: 18px;
		}
	}

	.card-list {
		height: 200px;
		overflow: auto;
		padding: 0 10px;
		.el-card {
			height: 40px;
			margin: 10px 0;
			display: flex;
			align-items: center;
			cursor: pointer;
		}
		.select {
			background: rgb(252, 181, 181);
		}
	}
</style>